package com.ceair.aspect;

import com.ceair.entity.dto.SysLogDto;
import com.ceair.entity.model.UserInfo;
import com.ceair.kafka.producer.SysLogProducer;
import com.ceair.util.UserInfoUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/**
 * @author wangbaohai
 * @ClassName LogAspect
 * @description: 日志切面
 * @date 2025年04月17日
 * @version: 1.0.0
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LogAspect {

    // 用于 JSON 处理
    private final ObjectMapper objectMapper;

    // 用户工具
    private final UserInfoUtils userInfoUtils;

    // Kafka 日志生产者
    private final SysLogProducer sysLogProducer;

    // 定义切点，拦截 controller 层的所有 public 方法
    @Pointcut("execution(public * com.ceair.controller..*(..))")
    public void controllerMethods() {}

    @Around("controllerMethods()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取当前用户信息
        UserInfo userInfo = userInfoUtils.getUserInfoFromAuthentication();

        // 获取当前 HTTP 请求对象
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(
                RequestContextHolder.getRequestAttributes())).getRequest();
        String requestUrl = request.getRequestURI();

        // 获取请求参数
        Object[] args = joinPoint.getArgs();

        // 转换为 JSON 字符串
        String requestParams = objectMapper.writeValueAsString(args);

        // 记录方法执行开始时间
        long startTime = System.currentTimeMillis();

        // 默认执行状态
        String status = "SUCCESS";
        String exceptionInfo = "";
        Object result = null;

        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Throwable ex) {
            // 发生异常，记录异常信息并标记为失败
            status = "FAILURE";
            exceptionInfo = ex.getMessage();
            throw ex;
        } finally {
            // 计算执行时间（毫秒）
            long executionTime = System.currentTimeMillis() - startTime;

            // 获取响应参数（目标方法的返回值）
            String responseResult = objectMapper.writeValueAsString(result);

            // 记录日志
            log.info("Request URL: {}, Execution Time: {} ms, Status: {}, Exception: {}, Request Params: {}, Response: {}",
                    requestUrl, executionTime, status, exceptionInfo, requestParams, responseResult);

            // 异步持久化日志
            String finalStatus = status;
            String finalExceptionInfo = exceptionInfo;
            CompletableFuture.runAsync(() -> sysLogProducer.sendSysLog(SysLogDto.builder()
                    .userName(Objects.isNull(userInfo) ? "system" : userInfo .getAccount())
                    .callDate(LocalDate.now())
                    .callTime(LocalTime.now())
                    .url(requestUrl)
                    .executionTime(executionTime)
                    .result(finalStatus)
                    .createdTime(LocalDateTime.now())
                    .requestParams(requestParams)
                    .responseResult(responseResult)
                    .exceptionInfo(finalExceptionInfo)
                    .build()));
        }

        return result;
    }

}
